<?php

namespace app\index\controller;

use Predis\Client;
use think\Controller;
use think\Cookie;
use think\Request;
use app\index\validate;
use app\index\model;
use think\Session;


class Login extends Controller
{
    public function login(Request $request)
    {
        $info = $request->post();
        // 判断是不是post传输
        if (request()->isAjax()) {
            $redis = new Client();
            // 获取用户ip
            $ip = Request::instance()->ip();
            // 将ip转化成字串
            $strIp = ip2long($ip);
            // 获取2小时内锁定的次数
            $lock = $redis->get('index:status:' . $strIp);
            // 判断状态码存不存在
            if (!empty($redis->get('index:status:' . $strIp))) {
                $res = [
                    'status' => false,
                    'msg' => '信息不正确,为了保证账户安全，系统已经将您账号锁定' . (1 * $lock * $lock) . '分钟',
                ];
                return $res;
            }

            // 接受前端数据
            $data = [
                'tel' => $info['tel'],
                'pwd' => $info['pass'],
            ];

            // 验证数据
            $validate = validate('Login');
            if (!$validate->check($data)) {
                $res = [
                    'status' => false,
                    'msg' => $validate->getError(),
                ];
                return res;
            }

            // 获取redis数据
            $id = $redis->get('index:name:' . $data['tel'] . ':id');
            // 验证 redis中数据
            if (!empty($id)) {
                // 调用redis验证
                $res = $this->redis($info);
                return $res;
            } else {
                // 调用数据库验证
                $res = $this->demo($info);
                return $res;
            }

        } else { // 不是post传输的数据报错
            $res = [
                'status' => false,
                'msg' => '你是不是走错了',
            ];
            return $res;
        }
    }

    // redis验证
    public function redis($data)
    {
        $redis = new Client();

        // 获取redis数据
        $id = $redis->get('index:name:' . $data['tel'] . ':id');
        // 验证 redis中数据
        if (!empty($id)) {
            $pwd = $redis->hget('index:' . $id, 'pwd');
            if ($pwd == MD5($data['pass'])) {
                $ip = Request::instance()->ip();

                // 更新数据库用户信息
                $list = [
                    'login_ip' => $ip,
                    'last_login_time' => time(),
                    'times' => $redis->hget('index:' . $id, 'times'),
                ];

                $dotime = model('Login');
                $dotime->uplogin($list, $redis->hget('index:' . $id, 'id'));

                // 判断用户没有有使用免登陆
                if (!empty($data['remember'])) {
                    Cookie('index', ['tel'=>$data['tel'],'pwd'=>MD5($data['pass'])], 7 * 24 * 3600);
                }
                session('index', ['pwd'=>MD5($data['pass']),'tel'=>$data['tel']]);

                $res = [
                    'status' => true,
                    'msg' => '登录成功',
                ];

                return $res;
            } else {
                // 获取用户ip
                $ip = Request::instance()->ip();
                // 将ip转化成字串
                $strIp = ip2long($ip);
                // 调用错误记录 查看用户2小时共错了多少次
                if ($this->err($strIp)) {
                    // 获取错误次数
                    $errNum = $redis->get('index:' . $strIp);
                    $res = [
                        'status' => false,
                        'msg' => '用户名或密码错误,再输入' . (5 - $errNum) . '次将被锁定',
                    ];
                    return $res;
                }
            }
        }
    }

    // 数据库验证
    public function demo($data)
    {
        $redis = new Client();
        // 请求数据库
        $index = model('Login');
        $res = $index->login($data);
        $ip = Request::instance()->ip();

        // 数据库没有用户信息
        if (!$res) {
            // 获取用户ip
            // 将ip转化成字串
            $strIp = ip2long($ip);
            // 调用错误记录 查看用户2小时共错了多少次
            if ($this->err($strIp)) {
                // 获取错误次数
                $errNum = $redis->get('index:' . $strIp);
                $res = [
                    'status' => false,
                    'msg' => '用户名或密码错误,再输入' . (5 - $errNum) . '次将被锁定',
                ];
                return $res;
            }
        } else {

            // 数据库有用户信息
            $list = [
                'login_ip' => $ip,
                'last_login_time' => time(),
                'times' => ++$res['times'],
            ];

            $dotime = model('Login');
            $dotime->uplogin($list, $res['id']);

            // 设置自增id
            $id = $redis->incr('index:id');
            // 判断用户没有有使用免登陆
            if (!empty($data['remember'])) {
                Cookie('index', ['tel'=>$data['tel'],'pwd'=>MD5($data['pass'])], 7 * 24 * 3600);
            }
            // 将用户数据存进session中
            session('index', ['pwd'=>MD5($data['pass']),'tel'=>$data['tel']]);

            // 将用户ID存入redis
            $redis->setex('index:name:' . $data['tel'] . ':id', '7200', $id);
            // 将用户信息以自增 id 存入redis(hash)
            $redis->hset('index:' . $id, 'pwd', MD5($data['pass']));
            $redis->hset('index:' . $id, 'name', $res['nickname']);
            $redis->hset('index:' . $id, 'id', $res['id']);
            $redis->hset('index:' . $id, 'times', ++$res['times']);

            $res = [
                'status' => true,
                'msg' => '登录成功',
            ];

            return $res;
        }
    }

    // 记录错误信息
    public function err($ip)
    {
        $redis = new Client();

        // 判断用户ip是不是2小时内第一次错误
        if (empty($redis->get('index:' . $ip))) {
            // 清楚之前的数据
            $redis->del('index.LockNum:' . $ip);

            $redis->setex('index.num:' . $ip, 7200, 1);
            // 将错误次数存入redis中,有效时间2小时
            $redis->setex('index:' . $ip, 7200, 1);
            return true;

            // 判断当前ip用户的错误次数小于4次
        } else if ($redis->get('index:' . $ip) < 4) {
            // 自增num
            $redis->incr('index.num:' . $ip);
            // 将用户的错误次数存进redis中 存入第一次剩余时间
            $redis->setex('index:' . $ip, 7200, $redis->get('index.num:' . $ip));
            return true;

        } else {
            // 当用户ip错误次数大于5次时禁用

            // 判断 2小时内是不是第一次锁定 不是自增1
            empty($redis->get('index:LockNum:' . $ip)) ? $redis->setnx('index:LockNum:' . $ip, 1) : $redis->incr('index:LockNum:' . $ip);

            $num = $redis->get('index:LockNum:' . $ip);

            // 设置有效期, 用户错误次数记录
            $redis->setex('index:status:' . $ip, (60 * $num * $num), $num);

            $this->error('信息不正确,为了保证账户安全，系统已经将您账号锁定' . (1 * $num * $num) . '分钟');
        }
    }

    //清除登录
    public function cancellation()
    {
        Cookie('index', null);
        session('index', null);
        $this->redirect('/');
    }
}
